﻿using System;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
using System.IO;
using System.Text;
using InfoJetSoft.Service.Entity;

namespace InfoJetSoft.Service.Util
{
	
	public class DOMUtil
	{
		
		public static string getNodeJetId(XmlNode node)
		{
			string nodeId = null;
			if (node is XmlAttribute)
			{
				XmlAttribute attribute = (XmlAttribute) node;
				//在Onkostendeclaratie.xsn中出现过传如xmlns:xml="http://www.w3.org/XML/1998/namespace"属性,OwnerElement为null.
				XmlElement parentElement = attribute.OwnerElement;
				if( parentElement == null )
				{
					return null;
				}
				string parentId = parentElement.GetAttribute(JetConstant.JetId);
				if (parentId.Length <= 0)
				{
					//不再需要抛出异常.
					//throw new InfoJetException("no jet id", "DU01");
					//CID 0107 //2008.08.31 //Begin
					return null;
					//CID 0107 //2008.08.31 //End
				}
				nodeId = parentId + "@" + attribute.Name;
			}
			else if (node is XmlElement)
			{
				XmlElement element = (XmlElement) node;
				nodeId = element.GetAttribute(JetConstant.JetId);
				if (nodeId.Length <= 0)
				{
					return null;
				}
			}
			else
			{
				return null;
			}
			return nodeId;
		}

		public static XmlDocument buildDoc(byte[] bytes)
		{
			MemoryStream stream = new MemoryStream(bytes);
			XmlDocument doc = new XmlDocument();
			doc.Load( stream );
			return doc;
		}

        //CID 1022 //2011.10.16 //Begin
        public static XmlDocument buildDocPreserveWhitespace(byte[] bytes)
        {
            MemoryStream stream = new MemoryStream(bytes);
            XmlDocument doc = new XmlDocument();
            //CID 0749 //2011.09.06 //Begin
            doc.PreserveWhitespace = true;
            //CID 0749 //2011.09.06 //End
            doc.Load(stream);
            return doc;
        }
        //CID 1022 //2011.10.16 //End
		
		public static XmlNode selectANode(XmlNode node, string filter, XmlNamespaceManager nsManager)
		{
			XmlNode	selectedNode = node.SelectSingleNode(filter, nsManager);
			return selectedNode;
		}
		
		public static XmlNodeList selectNodes(XmlNode node, string filter, int minCount, XmlNamespaceManager nsManager)
		{
			XmlNodeList nodeList = node.SelectNodes(filter, nsManager);
			if (nodeList == null)
			{
				throw new InfoJetException("invalidate selectNodes " + filter, "DU31");
			}
			if (minCount > 0 && nodeList.Count < minCount)
			{
				throw new InfoJetException("no enough node selected", "DU13");
			}
			return nodeList;
		}
		
		public static XmlNode selectOneNode(XmlNode node, string filter, XmlNamespaceManager nsManager)
		{
			XmlNode	selectedNode = node.SelectSingleNode(filter, nsManager);
			if (selectedNode == null)
			{
				throw new InfoJetException("no one node selected", "DU15");
			}
			return selectedNode;
		}

		//将XmlNode转换为Xml,如果Xml内容只包含Ascii字符,则按ASCII编码.
		public static string toOuterXmlWithoutEncoding(XmlNode node)
		{
			//根据Submit as string.xsn和Submit as string utf-8.xsn的测试,InfoPath提交的xml头都是<?xml version="1.0"?>.
			//不包含编码属性,encoding="UTF-8".
			//因为提交WS时已改成使用直接写OuterXml,而不是XmlDoc.Save,所以不需要再用ch > 127判断是否都是ASCII字符了.
			//但是根据测试,还是都要去掉UTF-8编码标记.
			string xml = node.OuterXml;
			xml = xml.Replace( " encoding=\"UTF-8\"?>", "?>" );
			return xml;
		}
		
		public static string toString(XmlNode node)
		{
			return node.OuterXml;
		}

		public static bool hasOneTextChild(XmlElement element)
		{
			XmlNodeList nodeList = element.ChildNodes;
			if ( (nodeList.Count <= 0) || (nodeList.Count == 1 && nodeList[ 0 ] is XmlText) )
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		
		public static void setEventAttribute(XmlElement element, string event_Renamed, string handler)
		{
			string preHandler = element.GetAttribute(event_Renamed);
			if (preHandler.Length <= 0)
			{
				element.SetAttribute(event_Renamed, handler);
			}
		}
		
		public static void removeJetId(XmlDocument doc)
		{
			XmlElement root = doc.DocumentElement;
			XmlNodeList elementList = root.SelectNodes( "//*" );
			foreach (XmlElement element in elementList)
			{
				element.RemoveAttribute(JetConstant.JetId);
			}
		}

		//CID 0331 //2009.07.21 //Begin
		public static void removeInnerJetId(XmlNode node) {
			XmlNodeList elementList = node.SelectNodes( ".//*" );
			foreach (XmlElement element in elementList) {
				element.RemoveAttribute(JetConstant.JetId);
			}
		}
		//CID 0331 //2009.07.21 //End
		
		public static void resetText(XmlElement element, string text)
		{
            //CID 1022 //2011.10.24 //Begin
            /*
			//CID 0411 //2009.09.30 //Begin
			ArrayList textNodeList = new ArrayList();
			foreach (XmlNode childNode in element.ChildNodes)
			{
				if (childNode is XmlText)
				{
					textNodeList.Add( childNode );
				}
			}
			foreach (XmlText textNode in textNodeList)
			{
				element.RemoveChild(textNode);
			}
			//CID 0411 //2009.09.30 //End
             */
            while (element.ChildNodes.Count > 0)
            {
                element.RemoveChild(element.ChildNodes[0]);
            }
            //CID 1022 //2011.10.24 //End
            XmlText newText = element.OwnerDocument.CreateTextNode( text );
			element.AppendChild( newText );
		}
		
		public static bool setNodeValue(XmlNode node, string value_Renamed)
		{
			if( value_Renamed == null )
			{
				return false;
			}
			if (node is XmlElement)
			{
				XmlElement element = (XmlElement) node;
				if( element.InnerText.Equals( value_Renamed ) )
				{
					return false;
				}
				else
				{
                    //CID 0645 //2010.10.25 //Begin
                    if (value_Renamed.Length <= 0)
                    {
                        DOMUtil.removeChildNodes(element);
                        return true;
                    }
                    else
                    {
                        DOMUtil.resetText(element, value_Renamed);
                        return true;
                    }
                    //CID 0645 //2010.10.25 //End
				}
			}
			else if (node is XmlAttribute)
			{
				XmlAttribute attr = (XmlAttribute) node;
				if( attr.Value.Equals( value_Renamed ) )
				{
					return false;
				}
				else
				{
					attr.Value = value_Renamed;
					return true;
				}
			}
			return false;
		}
		
		public static string getNodeValue(XmlNode node)
		{
			if (node is XmlElement)
			{
				XmlElement element = (XmlElement) node;
				return element.InnerText;
			}
			else if (node is XmlAttribute)
			{
				XmlAttribute attr = (XmlAttribute) node;
				return attr.Value;
			}
			else
			{
				// 这里可能有问题.
				return node.Value;
			}
		}

		public static XmlElement renameElementName(XmlElement element, string name){
			XmlDocument doc = element.OwnerDocument;
			XmlElement parentElement = (XmlElement)element.ParentNode;
			XmlElement newElement = doc.CreateElement( name );
			
			ArrayList attrList = new ArrayList();
			foreach (XmlAttribute attr in element.Attributes){
				attrList.Add( attr );
			}
			foreach (XmlAttribute attr in attrList){
				element.RemoveAttributeNode( attr );
				newElement.SetAttributeNode( attr );
			}

			ArrayList childList = new ArrayList();
			foreach (XmlNode child in element.ChildNodes){
				childList.Add( child );
			}
			foreach (XmlNode child in childList){
				element.RemoveChild( child );
				newElement.AppendChild( child );
			}

			parentElement.ReplaceChild( newElement , element );
			return newElement;
		}

		public static bool hasElementChildren( XmlElement element ){
			foreach( XmlNode node in element.ChildNodes ){
				if( node is XmlElement ){
					return true;
				}
			}
			return false;
		}

		public static void removeChildNodes( XmlElement element ){
			ArrayList childNodeList = new ArrayList();
			foreach( XmlNode childNode in element.ChildNodes ){
				childNodeList.Add( childNode );
			}
			foreach( XmlNode childNode in childNodeList ){
				element.RemoveChild( childNode );
			}
		}

        //CID 0907 //2011.05.13 //Begin
        public static void removeNode(XmlNode node)
        {
            if (node is XmlAttribute)
            {
                XmlAttribute attr = node as XmlAttribute;
                attr.OwnerElement.RemoveAttributeNode(attr);
            }
            else
            {
                node.ParentNode.RemoveChild(node);
            }
        }
        //CID 0907 //2011.05.13 //End

		public static XmlElement findElementByLocalNames( XmlDocument doc, string[] names ){
			XmlElement root = doc.DocumentElement;
			XmlElement parentElement = root;
			XmlElement foundElement = null;
			int i = 0;
			for( i = 0; i < names.Length; i ++ ){
				string name = names[ i ];
				if( parentElement == null ){
					break;
				}
				foreach( XmlNode node in parentElement.ChildNodes ){
					if( node is XmlElement ){
						XmlElement element = (XmlElement) node;
						if( element.LocalName.Equals( name ) ){
							parentElement = element;
							foundElement = element;
							continue;
						}
					}
				}
			}
			if( foundElement != null && i == names.Length ){
				return foundElement;										 
			}
			return null;
		}

		public static XmlElement findFirstChildElement( XmlElement element ){
			foreach( XmlNode node in element.ChildNodes ){
				if( node is XmlElement ){
					return (XmlElement) node;
				}
			}
			return null;
		}

		public static XmlElement findChildElementByLocalName( XmlElement element, string localName ){
			foreach( XmlNode childNode in element.ChildNodes )
			{
				if( childNode is XmlElement )
				{
					if( childNode.LocalName.Equals( localName ) )
					{
						return (XmlElement)childNode;
					}
				}
			}
			return null;
		}

		public static ArrayList findChildElementListByLocalName( XmlElement element, string localName )
		{
			ArrayList childList = new ArrayList();
			foreach( XmlNode childNode in element.ChildNodes )
			{
				if( childNode is XmlElement )
				{
					if( childNode.LocalName.Equals( localName ) )
					{
						childList.Add( childNode );
					}
				}
			}
			return childList;
		}

		public static XmlElement findChildElementByLocalNameAndAttr( XmlElement element, string localName, string attrName, string attrValue )
		{
			ArrayList elementList = findChildElementListByLocalName( element, localName );
			foreach( XmlElement foundElement in elementList )
			{
				string foundAttrValue = foundElement.GetAttribute( attrName );
				if( foundAttrValue != null && foundAttrValue.Equals( attrValue ) )
				{
					return foundElement;
				}
			}
			return null;
		}

		public static XmlElement findAncestorElementByLocalName( XmlElement element, string localName )
		{
			XmlElement parentElement = null;
			if( element.ParentNode is XmlElement )
			{
				parentElement = (XmlElement)element.ParentNode;
			}
			else
			{
				return null;
			}
			while( parentElement != null )
			{
				if( parentElement.LocalName.Equals( localName ) )
				{
					return parentElement;
				}
				if( parentElement.ParentNode is XmlElement )
				{
					parentElement = (XmlElement)parentElement.ParentNode;
				}
				else
				{
					return null;	
				}
			}
			return null;
		}

		public static string getNodeNamespaceUri( XmlDocument doc, string nodeName )
		{
			if( nodeName.StartsWith( "@" ) )
			{
				nodeName = nodeName.Substring( 1 );
			}
			int index = nodeName.IndexOf( ":" );
			if( index < 0 )
			{
				return doc.DocumentElement.GetNamespaceOfPrefix( "" );
			}
			else
			{
				string prefix = nodeName.Substring( 0, index );
				return doc.DocumentElement.GetNamespaceOfPrefix( prefix );
			}
		}

		public static string getNodeNamePrefix( string nodeName )
		{
			int index = nodeName.IndexOf( ":" );
			if( index < 0 )
			{
				return "";
			}
			else
			{
				string prefix = nodeName.Substring( 0, index );
				return prefix;
			}
		}

		public static string getNodeNameWithoutPrefix( string nodeName )
		{
			int index = nodeName.IndexOf( ":" );
			if( index < 0 )
			{
				return nodeName;
			}
			else
			{
				if( nodeName.StartsWith( "@" ) )
				{
					return "@" + nodeName.Substring( index + 1 );
				}
				else
				{
					return nodeName.Substring( index + 1 );
				}
			}
		}

		public static string getNodeXPathName( XmlNode node )
		{
			if( node is XmlAttribute )
			{
				return "@" + node.Name;
			}
			return node.Name;
		}

		public static XmlNode findNodeByJetId( Form form, string jetId )
		{
			string[] ids = FieldUtil.parseJetId( jetId );
			string elementId = ids[0];
			string attributeName = ids[1];
			
			string filter = "//*[@" + JetConstant.JetId + "='" + elementId + "']";
			XmlElement element = (XmlElement) DOMUtil.selectANode(form.XmlDoc.DocumentElement, filter, form.XmlNsResolver);
			if( element != null )
			{
				if( attributeName.Length <= 0 )
				{
					return element;
				}
				else
				{
					return element.GetAttributeNode( attributeName );
				}
			}
			return null;
		}

        //CID 0755 //2011.01.06 //Begin
        public static XmlNode findSDSNodeByJetId(Form form, string jetId)
        {
            DataObject dataObject = SDSIdUtil.findDataObjectByJetId(form, jetId);
            if(dataObject != null)
            {
                XmlDocument sdsDoc = form.DataTable[dataObject.Name] as XmlDocument;
                if (sdsDoc != null)
                {
                    return findNodeByJetId(sdsDoc, jetId);
                }
            }
            return null;
        }
        //CID 0755 //2011.01.06 //End

		//CID 0236 //2009.03.04 //Begin
		public static XmlNode findNodeByJetId( XmlDocument doc, string jetId )
		{
			NamespaceResolver nsResolver = new NamespaceResolver( doc );

			string[] ids = FieldUtil.parseJetId( jetId );
			string elementId = ids[0];
			string attributeName = ids[1];
			
			string filter = "//*[@" + JetConstant.JetId + "='" + elementId + "']";
			XmlElement element = (XmlElement) DOMUtil.selectANode(doc.DocumentElement, filter, nsResolver);
			if( element != null )
			{
				if( attributeName.Length <= 0 )
				{
					return element;
				}
				else
				{
					return element.GetAttributeNode( attributeName );
				}
			}
			return null;
		}
		//CID 0236 //2009.03.04 //End

		public static string getNodePath( XmlNode node )
		{
			StringBuilder path = new StringBuilder();
			XmlElement element = null;
			if( node is XmlAttribute )
			{
				path.Append( "@" + node.Name );	
				XmlAttribute attr = (XmlAttribute) node;
				element = attr.OwnerElement;
			}
			else if( node is XmlElement )
			{
				element = (XmlElement)node;
			}
			else
			{
				return "";
			}

			while( !element.Equals( node.OwnerDocument.DocumentElement ) )
			{
				if( path.Length > 0 )
				{
					path.Insert( 0, element.Name + "/" );
				}
				else
				{
					path.Insert( 0, element.Name );
				}
				element = (XmlElement)element.ParentNode;
			}
		
			if( path.Length > 0 )
			{
				path.Insert( 0, element.Name + "/" );
			}
			else
			{
				path.Insert( 0, element.Name );
			}

			path.Insert( 0, "/" );

			return path.ToString();
		}

        //CID 0911 //2011.05.09 //Begin
        public static string getNodeUriPath(XmlNode node)
        {
            StringBuilder path = new StringBuilder();
            XmlElement element = null;
            if (node is XmlAttribute)
            {
                path.Append("@{" + node.NamespaceURI + "}:" + node.LocalName);
                XmlAttribute attr = (XmlAttribute)node;
                element = attr.OwnerElement;
                //CID 0918 //2011.05.20 //Begin
                if (element == null)
                {
                    return "";
                }
                //CID 0918 //2011.05.20 //End
            }
            else if (node is XmlElement)
            {
                element = (XmlElement)node;
            }
            else
            {
                return "";
            }

            while (!element.Equals(node.OwnerDocument.DocumentElement))
            {
                //CID 1014 //2011.09.05 //Begin
                if (path.Length > 0)
                {
                    path.Insert(0, "{" + element.NamespaceURI + "}:" + element.LocalName + "/");
                }
                else
                {
                    path.Insert(0, "{" + element.NamespaceURI + "}:" + element.LocalName);
                }
                //CID 1014 //2011.09.05 //End
                element = (XmlElement)element.ParentNode;
            }

            if (path.Length > 0)
            {
                path.Insert(0, "{" + element.NamespaceURI + "}:" + element.LocalName + "/");
            }
            else
            {
                path.Insert(0, "{" + element.NamespaceURI + "}:" + element.LocalName);
            }

            path.Insert(0, "/");

            return path.ToString();
        }
        //CID 0911 //2011.05.19 //End

		public static string getControlBindingExpr( View view, string binding )
		{
            //CID 0714 //2010.11.29 //Begin
            /*
			string bindingValue = null;
			if (binding.StartsWith("@")) 
			{
				bindingValue = "{./@" + JetConstant.JetId + "}" + binding;
			}
			else if (binding.IndexOf("@") > 0) 
			{
				StringTokenizer atTokenizer = new StringTokenizer(binding, "@");
				string elementBinding = atTokenizer.NextToken();
				string attributeBinding = atTokenizer.NextToken();
				bindingValue = "{" + elementBinding + "@" + JetConstant.JetId + "}@" + attributeBinding;
			}
			else 
			{
				bindingValue = "{" + binding + "/@" + JetConstant.JetId + "}";
			}
			return bindingValue;
             */
            return "{" + NamespaceUtil.toFullName(view.XdExtensionPrefix, "GetJetId(") + binding + ")}";
            //CID 0714 //2010.11.29 //End
		}

        //CID 0773 //2011.02.10 //Begin
        public static string getControlJsonXmlExpr(View view, string binding, string filter)
        {
            return "{" + NamespaceUtil.toFullName(view.XdExtensionPrefix, "GetElementJsonXml(") + binding + ", '" + filter + "')}";
        }
        //CID 0787 //2011.02.16 //End

		public static string getSectionBindingExpr( View view, string binding )
		{
			//CID 0714 //2010.11.29 //Begin
			/*
            string bindingValue = null;
			if (binding.IndexOf("@") >= 0)
			{
				int index = binding.IndexOf("@");
				string attributeBinding = binding.Substring(index, (binding.Length) - (index));
                bindingValue = "{../@" + JetConstant.JetId + "}" + attributeBinding;
            }
			else
			{
				bindingValue = "{./@" + JetConstant.JetId + "}";
			}
			return bindingValue;
             */
            return "{" + NamespaceUtil.toFullName(view.XdExtensionPrefix, "GetJetId(") + ".)}";
            //CID 0714 //2010.11.29 //End
		}

		//判断Node是否为JetId属性.
		public static bool isJetId( XmlNode node )
		{	
			if( node is XmlAttribute && node.Name.Equals( JetConstant.JetId ) )
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		public static bool isChildJetId( XmlNode node, string jetId )
		{
			string parentJetId = DOMUtil.getNodeJetId( node );
			string indexPrefix = parentJetId.Substring( 0, parentJetId.Length - node.Name.Length );
			if( jetId.StartsWith( indexPrefix ) )
			{
				return true;
			}
			else
			{
				return false;
			}
		}

        //CID 0912 //2011.05.18 //Begin
        public static bool isChildNode(XmlNode node, XmlNode cNode)
        {
            foreach (XmlNode childNode in node.ChildNodes)
            {
                if (childNode.Equals(cNode))
                {
                    return true;
                }
            }
            return false;
        }
        //CID 0912 //2011.05.18 //End

        //CID 0947 //2011.06.13 //Begin
        public static bool isAncestorNode(XmlNode node, XmlNode aNode)
        {
            XmlNode parentNode = node.ParentNode;
            while (parentNode != null)
            {
                if (parentNode.Equals(aNode))
                {
                    return true;
                }
                parentNode = parentNode.ParentNode;
            }
            return false;
        }
        //CID 0947 //2011.06.13 //End

		//判断节点是否已经添加到了文档中。
		public static bool isInDocument( XmlNode node )
		{
			XmlElement element = null;
			if( node is XmlAttribute )
			{
				element = ((XmlAttribute)node).OwnerElement;
			}
			else
			{
				element = (XmlElement)node;
			}
			if( element == null )
			{
				return false;
			}
			XmlNode parentNode = element.ParentNode;
			while( parentNode != null )
			{
				if( parentNode is XmlDocument )
				{
					return true;
				}
				parentNode = parentNode.ParentNode;
			}
			return false;
		}

		//CID 0216 //2009.01.21 //Begin
		public static XmlNode getOwnerNode( XmlNode node )
		{
			if( node is XmlAttribute )
			{
				return ((XmlAttribute)node).OwnerElement;
			}
			else
			{
				return node.ParentNode;
			}
		}
		//CID 0216 //2009.01.21 //End

		//CID 0216 //2009.01.21 //Begin
		public static bool hasOwnerNode( XmlNode node )
		{
			if( node is XmlAttribute )
			{
				return ((XmlAttribute)node).OwnerElement != null;
			}
			else
			{
				return node.ParentNode != null;
			}
		}
		//CID 0216 //2009.01.21 //End

		//CID 0238 //2009.03.08 //Begin
		public static String getElementPath( XmlElement element )
		{
			StringBuilder pathBuffer = new StringBuilder();
			pathBuffer.Append( "/" + element.Name );
			XmlNode parentNode = element.ParentNode;
			while( parentNode != null && (parentNode is XmlElement) )
			{
				XmlElement parentElement = (XmlElement) parentNode;
				pathBuffer.Insert( 0 , "/" + parentElement.Name );
				parentNode = parentElement.ParentNode;
			}
			return pathBuffer.ToString();
		}
		//CID 0238 //2009.03.08 //End

		//CID 0238 //2009.03.09 //Begin
		public static ArrayList toArrayList( XmlNodeList nodeList )
		{
			ArrayList itemNodeList = new ArrayList();
			foreach( XmlNode node in nodeList )
			{
				itemNodeList.Add( node );
			}
			return itemNodeList;
		}
		//CID 0238 //2009.03.09 //End

		//CID 0265 //2009.04.01 //Begin
		public static XmlText getLastTextNode( XmlElement element )
		{
			XmlText textNode = null;
			foreach( XmlNode childNode in element.ChildNodes )
			{
				if( childNode is XmlText )
				{
					textNode = childNode as XmlText;
				}
			}
			return textNode;
		}
		//CID 0265 //2009.04.01 //End

        //CID 0828 //2011.03.10 //Begin
        public static int getChildElementIndex(XmlElement parentElement, XmlElement childElement)
        {
            int index = -1;
            foreach (XmlNode childNode in parentElement.ChildNodes)
            {
                if (childNode is XmlElement)
                {
                    index++;
                }
            }
            return index;
        }
        //CID 0828 //2011.03.10 //End
	}
}